﻿using ACC.Business;
using ACC.Business.Process;
using ACC.Business.Utils;
using ACC.Data.ACCLog;
using ACC.Data.Comm;
using ACC.Data.Entities.Common;
using ACC.Data.Entities.Mes;
using ACC.Data.Line;
using ACC.Device;
using ACC.Device.Client;
using ACC.Device.PLC;
using ACC.Device.PLC.Siemens;
using ACC.Interface.Extensions;
using ACC.LineDevice.KukaPack;
using iPlant.Features.WOMSClient.Entity;
using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Text;

namespace Script
{
    /// <summary>
    /// 帖加热膜
    /// OP L1M03090, STATION L1M13091
    /// </summary>
    public class L1M03090 : StnProcessKukaPack
    {
        string[] barcodes = new string[] { };

        public L1M03090(StnRunningData data)
            : base(data)
        {
            //_data.ProcessUnitIDWhenLoad = true;
            IsACCReport = true;
            IsReport = true;
            // 不用基类的处理托盘逻辑
            IsPalletRelationSN = false;
        }

        protected override ACCDevice CreateDevice()
        {
            ACCDevice dev = base.CreateDevice();
            if (kukaSiemensDev != null)
            {
                kukaSiemensDev.DB190 = 800;
                kukaSiemensDev.DB190_Offset = 5000;
                kukaSiemensDev.DB192 = 80;
                kukaSiemensDev.DB192_PLC_Offset = 5066; // TO-DO: 66 ?
                kukaSiemensDev.DB193 = 800;
                kukaSiemensDev.DB193_PLC_Offset = 5034;
                kukaSiemensDev.DB193_ACC_Offset = 5068;
                kukaSiemensDev.DB194 = 800;
                kukaSiemensDev.DB194_PLC_Offset = 5034;
                kukaSiemensDev.DB194_PLC_Data_Offset = 5110;
            }

            return dev;
        }

        BomItemCfg mzCfg, jtCfg, gbCfg;

        public override void ChangePartNo(RuningPartNo newpartno)
        {
            base.ChangePartNo(newpartno);

            if (newpartno != null)
            {
                mzCfg = _data.PartNo.BomCfg.GetBomItemCfgByIDName("模组").Clone();
                jtCfg = _data.PartNo.BomCfg.GetBomItemCfgByIDName("模组基体").Clone();
                gbCfg = _data.PartNo.BomCfg.GetBomItemCfgByIDName("GBSN").Clone();

                mzCfg.QtyPer = GetBomItemQty("模组");
                jtCfg.QtyPer = GetBomItemQty("模组基体");
                gbCfg.QtyPer = GetBomItemQty("GBSN");

                _data.Components = new BomItemCfg[] { mzCfg, jtCfg, gbCfg };
            }
        }

        public override ACCCode ReadLoadParam(ACCDevice dev, out ACCDevice.LoadParam param)
        {
            string orderNo = string.Empty, partNo = string.Empty;
            materialTypeCount = -1; // 防止在底层进行扫料操作

            // 根据PLC给的信号位确定左、中、右模组, 做自动换型
            Position = ReadPosition((PLCDevice)kukaSiemensDev).ToString(); // 1:A 右模组、2:B 中模组,3:C 左模组

            IsACCReport = false;
            ACCCode rs = base.ReadLoadParam(dev, out param);
            IsACCReport = true;

            // 使用托盘号关联的工站
            if (rs == ACCCode.ACCOK && !string.IsNullOrEmpty(param.UnitSN))
            {
                #region 模组内部码由ACC生成的情况
                string jtBarcode = string.Empty;    // 模组基体码
                string modelBarcode = string.Empty; // 模组内部码
                string gbBarcode = string.Empty;    // 模组国标码
                PalletNo = param.UnitSN;
                param.UnitSN = string.Empty;

                //根据托盘号获取基体码   
                string[] u = this.GetPallet(PalletNo);
                if (u != null && u.Length > 0)
                {
                    jtBarcode = u[0];
                }

                //// 是否返工件
                bool isRwk = string.IsNullOrEmpty(jtBarcode) ? false : IsReworkUnitSN(jtBarcode, out partNo);
                int plannedQty;
                var woCurrent = _womsProcess.GetCurrentWorkOrder();
                string currentWoNo = woCurrent == null || woCurrent.IsNull ? string.Empty : woCurrent.Header.WONo;
                orderNo = woCurrent == null || woCurrent.IsNull ? string.Empty : woCurrent.Header.PONo;
                if (isRwk)
                {
                    var unit = UnitDataProcess.GetWIPUnit(_lineData, jtBarcode);
                    if (unit != null)
                    {
                        param.UnitSN = modelBarcode = unit.UnitSN;
                        partNo = unit.PartNo;
                        // 说明获取到的是老托盘，PLC没有新的基体码
                        if (param.UnitSN == jtBarcode)
                            jtBarcode = string.Empty;

                        // 工单切换和换型
                        var wono = GetWorkOrderByUnitSN(_lineData.Line, unit.UnitSN, out orderNo, out plannedQty);
                        if (string.IsNullOrEmpty(wono))
                        {
                            // 获取该件的工单
                            woCurrent = _womsProcess.GetWorkOrderByPartNo(_lineData.Line, unit.PartNo);
                            wono = woCurrent.IsNull ? string.Empty : woCurrent.Header.WONo;
                            orderNo = woCurrent.IsNull ? string.Empty : woCurrent.Header.PONo;
                            partNo = woCurrent.IsNull ? unit.PartNo : woCurrent.Header.PartNo;

                            if (string.IsNullOrEmpty(wono))
                            {
                                // 如果没有工单则获取下一个待生产工单
                                wono = GetWorkOrder(_lineData.Line, Position == "1" ? "A" : (Position == "2" ? "B" : "C"), out partNo, out orderNo, out plannedQty);
                                woCurrent = _womsProcess.GetWorkOrderByWorkOrderNo(_lineData.Line, wono);
                                orderNo = woCurrent.IsNull ? string.Empty : woCurrent.Header.PONo;
                                partNo = woCurrent.IsNull ? unit.PartNo : woCurrent.Header.PartNo;
                            }
                        }
                        // 当前工单和要生产的件的工单不一致，要切换工单
                        if (!string.IsNullOrEmpty(wono) && currentWoNo != wono)
                        {
                            // 切换工单
                            SetCurrentWorkOrder(wono, partNo);
                        }

                        if (string.IsNullOrEmpty(gbBarcode) && unit.GetUnitIDByIDName("GBSN") != null)
                        {
                            gbBarcode = unit.GetUnitIDByIDName("GBSN").IDValue;
                        }

                        if (string.IsNullOrEmpty(jtBarcode) && unit.GetUnitIDByIDName("模组基体") != null)
                        {
                            jtBarcode = unit.GetUnitIDByIDName("模组基体").IDValue;
                        }

                        if (string.IsNullOrEmpty(wono))
                        {
                            // 没有工单需要生产
                            return rs = ACCCode.UserDef_100;
                        }

                        currentWoNo = wono;
                    }
                }
                else
                {
                    // 从下达的工单中取得一个工单
                    // 取得方法:已下达的工单（STATUS = 1）按照【SORT】字段升序排序后的第一个工单
                    string wono = GetWorkOrder(_lineData.Line, Position == "1" ? "A" : (Position == "2" ? "B" : "C"), out partNo, out orderNo, out plannedQty);
                    if (!string.IsNullOrEmpty(wono) && currentWoNo != wono)
                    {
                        // 更新当前工单
                        SetCurrentWorkOrder(wono, partNo);
                    }

                    if (string.IsNullOrEmpty(wono))
                    {
                        // 没有工单需要生产
                        return rs = ACCCode.UserDef_100;
                    }

                    currentWoNo = wono;
                }

                if (string.IsNullOrEmpty(jtBarcode))
                {
                    // 可能是空托盘，未绑定模组基体码，也有可能托盘号错误等其他原因
                    return rs = ACCCode.Unit_Barcode_Empty;
                }

                // 如果工单号为空、说明还没有进行生产
                //if (string.IsNullOrEmpty(currentWoNo))
                //{
                //}
                rs = AutoChangePartNo(partNo, ref param);

                if (!string.IsNullOrEmpty(modelBarcode))
                {
                    // 检查工单状态
                    rs = _womsProcess.CheckWorkOrder(true, modelBarcode);

                    // 返回ACCCode.UserDef_104（工单已满）、则获取下一个工单(工单完成自动切换工单)
                    if (rs == ACCCode.UserDef_104)
                    {
                        // 从下达的工单中取得下一个工单
                        // 取得方法:已下达的工单（STATUS = 1）按照【SORT】字段升序排序、工单号不等于当前工单号的第一个工单作为下一个要生产的工单
                        currentWoNo = GetNewWorkOrder(_lineData.Line, Position == "1" ? "A" : (Position == "2" ? "B" : "C"), currentWoNo, out partNo, out orderNo);
                        if (!string.IsNullOrEmpty(currentWoNo))
                        {
                            rs = AutoChangePartNo(partNo, ref param);
                            // 更新当前工单
                            SetCurrentWorkOrder(currentWoNo, partNo);
                        }
                        else if (string.IsNullOrEmpty(currentWoNo))
                        {
                            // 没有工单需要生产
                            return rs = ACCCode.UserDef_100;
                        }
                    }
                }
                else
                {
                    // TO-DO: 生成模组内部码和国标码
                    // 根据左中右生成模组内部码 , 模组基体码里第一个字符代表模组生产的区域
                    string zone = string.IsNullOrEmpty(jtBarcode) ? "2" : jtBarcode.Substring(0, 1);
                    if (zone != "2" && zone != "3") // 防止是条码都由ACC生成升级前的件
                        zone = "2";
                    _data.PartNo.Variables["ZONE"] = zone;
                    // [PARTNO][LINE,SITE][CY][M][D][PARTNO,ZONE][COUNTER,MZSN,6]
                    param.UnitSN = modelBarcode = PartTypeTagProcess.GetPartTypeTagValue(_data.PartNo.BomCfg, "MZSN", logger).Replace("-", "");
                    var attrs = GetOrderAttributes(_womsProcess.GetCurrentWorkOrder().Header.PONo);
                    _data.PartNo.Variables["CELL_TYPE"] = attrs["CELL_TYPE"];
                    _data.PartNo.Variables["MODULE_SPEC"] = attrs["MODULE_SPEC"];
                    // 053M[PARTNO,CELL_TYPE][PARTNO,MODULE_SPEC]00002[PARTNO,ZONE][CY][M][D][COUNTER,GBSN,7] 
                    gbBarcode = PartTypeTagProcess.GetPartTypeTagValue(_data.PartNo.BomCfg, "GBSN", logger);
                }

                // 检查工单状态
                rs = _womsProcess.CheckWorkOrder(true, param.UnitSN);
                StnEventLog.Log(_data, StnLog.LogType.Warning, "WoNo = " + currentWoNo);
                //if(rs == ACCCode.ACCOK)
                //{
                //    rs = AutoChangePartNo(partNo, ref param);
                //}

                if (rs != ACCCode.ACCOK)
                {
                    return rs;
                }

                param.UnitSN = modelBarcode;
                param.ComponentSN = new string[] { jtBarcode, gbBarcode };
                param.PartTypeID = _data.PartNo == null ? 0 : (int)_data.PartNo.BomCfg.PartTypeID;
                param.PartNo = _data.PartNo;
                #endregion

            }

            if (rs == ACCCode.ACCOK)
            {
                //materialTypeCount = 1;      // 本站需要扫一种物料
                materialTypeCount = GetMaterialCount();
                if (dev is SiemensDeviceKukaPack && materialTypeCount > 0)
                {
                    rs = HandleScanMaterial(dev, orderNo/*param.UnitSN*/);
                }
            }

            return rs;
        }

        public override string GetMaterialBarcode(int index)
        {
            byte[] data = new byte[64];
            byte[] temp = new byte[62];
            if (Position == "1")        // 左模组两种物料分别放在位置1、位置2
            {
                // 左模组两种物料分别放在位置1、位置2
            }
            else if (Position == "2")
            {
                // 中模组一种物料放在位置3
                index = 2;
            }
            else if (Position == "3")
            {
                // 右模组一种物料放在位置4、5
                index = index + 3;
            }

            ((SiemensDevice)_Device).ReadDBBytes(((SiemensDevice)_Device).DB193, kukaSiemensDev.DB190_Offset + 600 + (index * 66), data);
            Array.Copy(data, 2, temp, 0, temp.Length);
            string _materialBarcode = Encoding.ASCII.GetString(temp);
            if (_materialBarcode != null && _materialBarcode.Length > data[1])
            {
                _materialBarcode = _materialBarcode.Substring(0, data[1]);
            }
            return _materialBarcode;
        }

        public override ACCCode SendLoadResult(ACCDevice dev, ACCDevice.LoadResult result)
        {
            if (result.ErrorCode == ACCCode.ACCOK && _data.LastLoadUnit != null)
            {
                // 给PLC写入模组内部码和模组国标码
                string modelBarcode = _data.LastLoadUnit.UnitSN; //_loadProcess._loadParam.UnitSN;
                string gbBarcode = _data.LastLoadUnit.GetUnitIDByIDName("GBSN").IDValue; //_loadProcess._loadParam.ComponentSN[1];
                string jtBarcode = _data.LastLoadUnit.GetUnitIDByIDName("模组基体").IDValue;
                // 绑定Pallet与内部码(SN1 = 模组内部码、SN2 = 基体内部码、SN3 = 模组国标码)
                // L1M04040 模组上输送线 换新托盘
                this.AddPallet(PalletNo, modelBarcode, jtBarcode, gbBarcode);

                // TO-DO: 确定5002是否正确
                SendBarcodeToPlc(new string[] { modelBarcode }, 5002, 30);
                // 给PLC写入模组国标码
                SendBarcodeToPlc(new string[] { gbBarcode }, 5072, 30);

                //ReportIn(dev, _data, result);
            }
            return base.SendLoadResult(dev, result);
        }

        public override ACCCode ReadUnloadParam(ACCDevice dev, out ACCDevice.UnloadParam param)
        {
            ACCCode rs = base.ReadUnloadParam(dev, out param);
            if (rs == ACCCode.ACCOK)
            {
                string sn = string.Empty;
                string[] v = this.GetPallet(param.UnitSN);
                if (v != null && v.Length > 0)
                {
                    param.UnitSN = v[0];
                    param.ComponentSN = new string[] { v[1], v[2] };
                    param.IsOk = true;
                }
            }

            return rs;
        }

        public override ACCCode SendUnloadResult(ACCDevice dev, ACCDevice.UnloadResult result)
        {
            //if (result.ErrorCode == ACCCode.ACCOK)
            //{
            //    ReportOut(dev, _data, _unloadProcess._unloadParam, result);
            //}
            return base.SendUnloadResult(dev, result);
        }

        public uint ReadPosition(PLCDevice device)
        {
            try
            {
                SiemensDevice dev = (SiemensDevice)device;
                MethodInfo method = dev.BaseDriver.GetType().GetMethod("ReadDBBytes");
                byte[] buf = new byte[1];
                Object[] param = new Object[] { dev.DB190, dev.DB190_Offset + 70, buf, true };
                if (!(bool)method.Invoke(dev.BaseDriver, param))
                {
                    throw new Exception("ReadCommValue fail");
                }
                return buf[0];
            }
            catch (Exception ex)
            {
                logger.Error(ex.StackTrace);
                return 0;
            }

        }
    }
}